using System;
using System.Data.Linq;

namespace RomanJendrusz.Amazon.ETL.Domain
{
    public class Book : IEquatable<Book>
    {
        private readonly EntitySet<BookAuthors> bookAuthors;
        private readonly EntitySet<CustomerReview> customerReview;
        private string currencyCode;
#pragma warning disable 649
        private DateTime updated;
        private EntitySet<SimiliarBook> similiarBooks;
#pragma warning restore 649

        public Book()
        {
            bookAuthors = new EntitySet<BookAuthors>(authorAdded, authorRemoved);
            customerReview = new EntitySet<CustomerReview>(reviewAddded, reviewRemoved);
            similiarBooks = new EntitySet<SimiliarBook>(similiarBookAdded, similiarBookRemoved);
        }

        private void similiarBookAdded(SimiliarBook obj)
        {
            obj.Book = this;
        }

        private void similiarBookRemoved(SimiliarBook obj)
        {
            obj.Book = null;
        }

        /// <summary>
        /// Gets or sets the asin.
        /// </summary>
        /// <value>The asin.</value>
        public string Asin { get; set; }

        /// <summary>
        /// Gets or sets the binding.
        /// </summary>
        /// <value>The binding.</value>
        public string Binding { get; set; }

        /// <summary>
        /// Gets or sets the detail page URL.
        /// </summary>
        /// <value>The detail page URL.</value>
        public string DetailPageURL { get; set; }

        /// <summary>
        /// Gets or sets the EAN.
        /// </summary>
        /// <value>The EAN.</value>
        public string EAN { get; set; }

        /// <summary>
        /// Gets or sets the ISBN.
        /// </summary>
        /// <value>The ISBN.</value>
        public string ISBN { get; set; }

        /// <summary>
        /// Gets or sets the label.
        /// </summary>
        /// <value>The label.</value>
        public string Label { get; set; }

        /// <summary>
        /// Gets or sets the orginal language of the book.
        /// </summary>
        /// <value>The language.</value>
        public string Language { get; set; }

        /// <summary>
        /// Gets or sets the manufacturer.
        /// </summary>
        /// <value>The manufacturer.</value>
        public string Manufacturer { get; set; }

        /// <summary>
        /// Gets or sets the number of pages.
        /// </summary>
        /// <value>The number of pages.</value>
        public int NumberOfPages { get; set; }

        /// <summary>
        /// Gets or sets the publication date.
        /// </summary>
        /// <value>The publication date.</value>
        public DateTime PublicationDate { get; set; }

        /// <summary>
        /// Gets or sets the publisher.
        /// </summary>
        /// <value>The publisher.</value>
        public string Publisher { get; set; }

        /// <summary>
        /// Gets or sets the studio.
        /// </summary>
        /// <value>The studio.</value>
        public string Studio { get; set; }

        /// <summary>
        /// Gets or sets the title.
        /// </summary>
        /// <value>The title.</value>
        public string Title { get; set; }

        /// <summary>
        /// Gets or sets the Universal product code.
        /// </summary>
        /// <value>The UPC.</value>
        public string UPC { get; set; }

        /// <summary>
        /// Gets or sets the price.
        /// </summary>
        /// <value>The price.</value>
        public decimal Price { get; set; }

        /// <summary>
        /// Gets or sets the price currency.
        /// </summary>
        /// <value>The price currency.</value>
        public Currency PriceCurrency
        {
            get { return Currency.GetCurrencyFor(currencyCode); }
            set { currencyCode = value.Code; }
        }

        /// <summary>
        /// Gets or sets the height.
        /// </summary>
        /// <value>The height.</value>
        public decimal Height { get; set; }

        /// <summary>
        /// Gets or sets the length.
        /// </summary>
        /// <value>The length.</value>
        public decimal Length { get; set; }

        /// <summary>
        /// Gets or sets the width.
        /// </summary>
        /// <value>The width.</value>
        public decimal Width { get; set; }

        /// <summary>
        /// Gets or sets the weigth.
        /// </summary>
        /// <value>The weigth.</value>
        public decimal Weight { get; set; }

        /// <summary>
        /// Gets or sets the number of items.
        /// </summary>
        /// <value>The number of items.</value>
        public int NumberOfItems { get; set; }

        /// <summary>
        /// Gets or sets the row updated.
        /// </summary>
        /// <value>The row updated.</value>
        public DateTime Updated
        {
            get { return updated; }
        }

        public EntitySet<BookAuthors> BookAuthors
        {
            get { return bookAuthors; }
            set { bookAuthors.Assign(value); }
        }

        public EntitySet<CustomerReview> CustomerReviews
        {
            get { return customerReview; }
            set { customerReview.Assign(value); }
        }

        public EntitySet<SimiliarBook> SimiliarBooks
        {
            get { return similiarBooks; }
            set {similiarBooks.Assign(value);}
        }

        #region IEquatable<Book> Members

        public bool Equals(Book book)
        {
            if (book == null) return false;
            if (!Equals(currencyCode, book.currencyCode)) return false;
            if (!Equals(Asin, book.Asin)) return false;
            if (!Equals(Binding, book.Binding)) return false;
            if (!Equals(DetailPageURL, book.DetailPageURL)) return false;
            if (!Equals(EAN, book.EAN)) return false;
            if (!Equals(ISBN, book.ISBN)) return false;
            if (!Equals(Label, book.Label)) return false;
            if (!Equals(Language, book.Language)) return false;
            if (!Equals(Manufacturer, book.Manufacturer)) return false;
            if (NumberOfPages != book.NumberOfPages) return false;
            if (!Equals(PublicationDate, book.PublicationDate)) return false;
            if (!Equals(Publisher, book.Publisher)) return false;
            if (!Equals(Studio, book.Studio)) return false;
            if (!Equals(Title, book.Title)) return false;
            if (!Equals(UPC, book.UPC)) return false;
            if (Price != book.Price) return false;
            if (Height != book.Height) return false;
            if (Length != book.Length) return false;
            if (Width != book.Width) return false;
            if (Weight != book.Weight) return false;
            if (NumberOfItems != book.NumberOfItems) return false;
            return true;
        }

        #endregion

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(this, obj)) return true;
            return Equals(obj as Book);
        }

        private void reviewRemoved(CustomerReview obj)
        {
            if (obj != null && obj.Book == this)
            {
                obj.Book = null;
            }
        }

        private void reviewAddded(CustomerReview obj)
        {
            if (obj != null)
            {
                obj.Book = this;
            }
        }

        private void authorRemoved(BookAuthors obj)
        {
            if (obj != null && obj.Book == this)
            {
                obj.Book = null;
            }
        }

        private void authorAdded(BookAuthors obj)
        {
            if (obj != null)
            {
                obj.Book = this;
            }
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }
}